#ifndef __SOCKET_HPP__
#define __SOCKET_HPP__
#include <sys/types.h>
#include <sys/socket.h>
#include "Log.hpp"
#include "InetAddr.hpp"
class Socket;
using socket_sptr = std::shared_ptr<Socket>;


LogType log;
class Socket
{
    protected:
    virtual void CreateSocket() = 0;
    virtual void BindSocket(InetAddr& addr) = 0;
    virtual void ListenSocket() = 0;
    virtual bool Connect(InetAddr& addr) = 0;
    virtual void Accept() = 0;
    public:
        void BuildListenSocket(InetAddr& addr)
        {
            CreateSocket();
            BindSocket(addr);
            ListenSocket();
        }
        void BuildClientSocket(InetAddr& addr)
        {
            CreateSocket();
            Connect(addr);
        }
};

const int gbacklog = 8;
class TCPSocket : public Socket
{
    protected:
    virtual void CreateSocket() override
    {
        _sockfd = socket(AF_INET,SOCK_STREAM,0);
        if(_sockfd < 0)
        {
            log(FATAL,__LINE__,__FILE__,"create socket error!\n");
            exit(FATAL);
        }
        log(INFO,__LINE__,__FILE__,"create socket success!\n");
    }
    virtual void BindSocket(InetAddr& addr) override
    {
        socklen_t s = sizeof(addr);
        int n = bind(_sockfd,reinterpret_cast<const sockaddr*>(&addr.Addr()),s);
        if(n < 0)
        {
            log(FATAL,__LINE__,__FILE__,"socket bind error!\n");
            exit(FATAL);
        }
        log(INFO,__LINE__,__FILE__,"socket bind error!\n");
    }
    virtual void ListenSocket()
    {
        int n = listen(_sockfd,gbacklog);
        if(n < 0)
        {
            log(ERROR,__LINE__,__FILE__,"set socket to listen status error!\n");
            exit(ERROR);
        }
        log(INFO,__LINE__,__FILE__,"set socket to listen success!\n");
    }
    virtual bool Connect(InetAddr& addr)
    {
        socklen_t len = sizeof(addr);
        int n = connect(_sockfd,reinterpret_cast<sockaddr*>(&addr.Addr()),len);
        if(n < 0)
        {
            log(ERROR,__LINE__,__FILE__,"client request connect error!\n");
            return false;
        }
        log(INFO,__LINE__,__FILE__,"client request connect success!\n");
        return true;
    }
    virtual socket_sptr Accept(InetAddr* addr)
    {
        struct sockaddr_in peer;
        socklen_t len = sizeof(peer);
        int sockfd = accept(_sockfd,reinterpret_cast<sockaddr*>(&peer),&len);
        if(sockfd < 0)
        {
            log(ERROR,__LINE__,__FILE__,"server accept error!\n");
        }
        else 
        {
            log(INFO,__LINE__,__FILE__,"server accept success!\n");
            *addr = peer;
            socket_sptr sockptr = std::make_shared<TCPSocket>(sockfd);
            return sockptr;
        }
    }
    protected:
        int _sockfd;
};



#endif
